package com.hisense.ovcloud.common3.tools;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Slf4j
public class LocalTimedCacheUtil<T> {
    private final ReentrantReadWriteLock rrwLock = new ReentrantReadWriteLock();

    private final TimedCache<String, T> lfuCache;

    public LocalTimedCacheUtil(int defaultTimeout, int schedulePrune){
        lfuCache = CacheUtil.newTimedCache(defaultTimeout);
        lfuCache.schedulePrune(schedulePrune);
    }

    public boolean saveToCache(String k, T v){
        try {
            rrwLock.writeLock().lock();
            lfuCache.put(k, v);
        } catch (Exception e) {
            log.error("failed to set cache for key {}, error is {}", k, e.getMessage());
        } finally {
            rrwLock.writeLock().unlock();
        }

        return true;
    }

    public boolean batchSave(Map<String, T> valueMap){
        try {
            rrwLock.writeLock().lock();
            valueMap.keySet().forEach(key -> lfuCache.put(key, valueMap.get(key)));
        } catch (Exception e) {
            log.error("failed to batchSave, error is {}", e.getMessage());
        } finally {
            rrwLock.writeLock().unlock();
        }

        return true;
    }

    public boolean batchDelete(List<String> keyList){
        try {
            rrwLock.writeLock().lock();
            keyList.forEach(lfuCache::remove);
        } catch (Exception e) {
            log.error("failed to batch delete the cache {}, error is {}", JSONUtil.toJsonStr(keyList), e.getMessage());
        } finally {
            rrwLock.writeLock().unlock();
        }

        return true;
    }

    public T getFromCache(String k){
        try {
            rrwLock.readLock().lock();
            if(lfuCache.containsKey(k)){
                return lfuCache.get(k);
            }
            return null;
        } catch (Exception e) {
            log.error("failed to get cache for key {}, error is {}", k, e.getMessage());
        } finally {
            rrwLock.readLock().unlock();
        }
        return null;
    }

    public boolean exists(String k){
        try {
            rrwLock.readLock().lock();
            return lfuCache.containsKey(k);
        } catch (Exception e) {
            log.error("failed to detect if key {} exists in cache, error is {}", k, e.getMessage());
        } finally {
            rrwLock.readLock().unlock();
        }
        return false;
    }
}
